/////////////////////////////////////////////////////////////////////////////////////
// Include Files
#include "Managers\ShaderManager.h"

#include "Cg\cg.h"

// TODO: platform independency
#include "Rendering\GLExt.h"
//#include "GLee\GLee.h"

#include "Cg\cgGL.h"

/////////////////////////////////////////////////////////////////////////////////////
// ISingleton<CShaderManager> Static Initialization
CShaderManager *ISingleton<CShaderManager>::m_pInstance = CE_NULL;

/////////////////////////////////////////////////////////////////////////////////////
// CShaderManager Implementation

void CShaderManager::Initialize()
{
	// create the context
	m_Context = cgCreateContext();
	assert(m_Context);

	// register standard OpenGL states
	// TODO: just use OpenGL shading language
	cgGLRegisterStates(m_Context);
}

void CShaderManager::Shutdown()
{
	// destroy the context TODO: currently this causes a very strange crash...

	//cgDestroyContext(m_Context);
	m_Context = CE_NULL;
}

void CShaderManager::LoadShaderFile( string_t _strFilename )
{
	ShaderLoad.Raise( new CShaderLoadEventArg(_strFilename) );
}

void CShaderManager::CreateShader( CShaderLoadEventArg &_rArg )
{
	string_t _strFilename = _rArg.GetName();

	// TODO version

	//string_t strFile = L"..\\Galleons\\Shaders\\" + _strFilename;
	//file_t file;
	//if( !file.Open(strFile, L"r") )
	//{
	//	assert(false);
	//}
	//uint_t uSize = file.GetSize();
	//byte_t *pData = new byte_t[uSize];
	//memset(pData, 0, uSize);
	//file.Read(pData, uSize);

	//// create the effect
	//CGeffect effect = cgCreateEffect(m_Context, (char *)pData, CE_NULL);

	// OLD version

	// Cg needs multi-byte
	char szFile[256];
	string_t strFile = L"..\\Galleons\\Shaders\\" + _strFilename;
	strFile.ToMultiByte(szFile, 256);

	// create the effect
	CGeffect effect = cgCreateEffectFromFile(m_Context, szFile, CE_NULL);
#ifdef _DEBUG
	char const *szError = cgGetLastListing(m_Context);
	assert(!szError);
#endif
	assert(effect);

	// get the first valid technique
	CGtechnique technique = cgGetFirstTechnique(effect);
	while( technique && !cgValidateTechnique(technique) )
	{
#ifdef _DEBUG
		szError = cgGetLastListing(m_Context);
#endif
		technique = cgGetNextTechnique(technique);
	}
#ifdef _DEBUG
	szError = cgGetLastListing(m_Context);
#endif
	assert(technique);

	// save the shader
	TShader shader;
	shader.strName   = _strFilename;
	shader.effect    = effect;
	shader.technique = technique;
	m_lstShaders.Append(shader);
}

CGeffect CShaderManager::GetEffect( string_t _strName )
{
	for( uint_t i = 0; i < m_lstShaders.GetSize(); ++i )
	{
		if( m_lstShaders[i].strName == _strName )
		{
			return m_lstShaders[i].effect;
		}
	}
	assert(false);
	return CGeffect();
}

CGtechnique CShaderManager::GetTechnique( string_t _strName )
{
	for( uint_t i = 0; i < m_lstShaders.GetSize(); ++i )
	{
		if( m_lstShaders[i].strName == _strName )
		{
			return m_lstShaders[i].technique;
		}
	}
	assert(false);
	return CGtechnique();
}

CGparameter CShaderManager::GetParameter( string_t _strShader, string_t _strName )
{
	for( uint_t i = 0; i < m_lstShaders.GetSize(); ++i )
	{
		if( m_lstShaders[i].strName == _strShader )
		{
			// Cg needs multi-byte
			char szName[256];
			_strName.ToMultiByte(szName, 256);

			return cgGetNamedEffectParameter(m_lstShaders[i].effect, szName);
		}
	}
	assert(false);
	return CGparameter();
}
